package com.parktech.sun.domain.repository.hibernate;

import com.parktech.sun.domain.repository.BaseRepository;
import com.parktech.sun.domain.repository.IndexRepository;
import com.parktech.sun.domain.repository.Page;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.List;

/**
 * User: Think
 * Date: 11-1-3
 * Time: 下午2:12
 */
public class BaseRepositoryImpl<T> extends HibernateDao implements BaseRepository<T> {

    private Class<T> clazz;

    /**
     * persistence interface.
     */


    public Session getCurrentSession() {
        return getSessionFactory().getCurrentSession();
        //return getSession();
    }


    @SuppressWarnings("unchecked")
    public BaseRepositoryImpl() {
        this.clazz = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
    }

    /*public BaseRepositoryImpl(final Class<T> persistentClas)
    {
        this.clazz = persistentClas;
    }*/

    public void update(T bean) {
        saveOrUpdateBean(bean);
    }

    public T merge(T bean) {
        return (T) getSession().merge(bean);
    }

    public void removeBeanByLogic(long id) {
    }

    public void removeBean(long id) {
        Session session = getSession();
        session.delete(session.get(clazz, id));
    }

    public void removeBeanByLogic(Class<T> clazz, long id) {
    }

    public T getBeanById(long id) {
        return (T) getSession().get(clazz, id);
    }

    public void removeBeanByLogic(int id) {

    }

    public void removeBean(int id) {
        getSession().delete(getBeanById(id));
    }

    public void removeBeanByLogic(Class<T> clazz, int id) {
    }

    public T getBeanById(int id) {
        return (T) super.getSession().get(clazz, id);
    }

    public Collection executePureSqlCol(String queryStr) {
        return getSession().createSQLQuery(queryStr).list();
    }

    public Collection executePureSqlCol(String queryStr, Object[] values) {
        SQLQuery sqlQuery = getSession().createSQLQuery(queryStr);
        for (int i = 0; i < values.length; i++) {
//            sqlQuery.set
        }
        return sqlQuery.list();
    }

    public Collection executePureSqlCol(String queryStr, Object[] values, int startAtIndex, int count) {
        return null;
    }

    public boolean executePureSql(String sql) {
        return getSession().createSQLQuery(sql).executeUpdate() > 0;
    }

    public Criteria createCriteria() {
        return getSession().createCriteria(clazz);
    }

    public Criteria createCriteria(Class clazz) {
        return getSession().createCriteria(clazz);
    }

    public Criteria createUndeleteCriteria() {
        return getSession().createCriteria(clazz);
    }

    public int countBeans(Criteria criteria) {
        return (int) countCriteriaResult(criteria);
    }

    public Collection listBeans(Criteria criteria, int startAtIndex, int count) {
        return criteria.setFirstResult(startAtIndex).setMaxResults(count).list();
    }

    public List listBeans(Criteria criteria) {
        return criteria.list();
    }

/*
    public <E> List<E> listBeans(Class<E> e) {
        return getSession().;
    }
*/

    public Collection listBeansBySql(String sql, int start, int size) {
        return getSession().createSQLQuery(sql).setFirstResult(start).setMaxResults(size).list();
    }

    public void clearThenSaveOrUpdateBean(T bean) {
        getSession().clear();
        getSession().saveOrUpdate(bean);
    }

    public void saveOrUpdateBean(T bean) {
        getSession().saveOrUpdate(bean);
    }

    public void updateBean(T bean) {
        getSession().update(bean);
    }

    public boolean isRepeated(String propertyName, String propertyValue, Serializable id, boolean isIncludeDeleted) {
        return false;
    }


    /**
     * 所有模块都可调用的公共分页显示方法，获取满足模糊条件的对象的总数目
     * @param clz
     * @param fieldColumns
     * @param searchValues
     * @return
     */
    public Integer getTotalSizeWithSimilarCondition(Class clz, List fieldColumns, List searchValues) {
        Criteria criteria = getSession().createCriteria(clz);
        if (fieldColumns != null && fieldColumns.size() != 0) {
            for (int k = 0; k < fieldColumns.size(); k++) {
                if (searchValues.get(k).getClass().getName().equals("java.lang.String"))
                    criteria.add(Restrictions.like((String) fieldColumns.get(k), ((String) searchValues.get(k)).trim(), MatchMode.ANYWHERE));
                else if (searchValues.get(k).getClass().getName().equals("[Ljava.lang.String;"))
                    criteria.add(Restrictions.in((String) fieldColumns.get(k), (String[]) searchValues.get(k)));
                else if (searchValues.get(k).getClass().getName().equals("[Ljava.lang.Long;"))
                    criteria.add(Restrictions.in((String) fieldColumns.get(k), (Long[]) searchValues.get(k)));
                else
                    criteria.add(Restrictions.eq((String) fieldColumns.get(k), searchValues.get(k)));
            }
        }
        criteria.setProjection(Projections.rowCount());
        List list = criteria.list();
        if (list != null && list.size() > 0) {
            return (Integer) list.get(0);
        } else {
            return 0;
        }
    }

     /**
      * 所有模块都可调用的公共分页显示方法，获取满足模糊条件的当前分页的对象列表
      * getPaginationObjectsWithSimilarCondition(class,1,20,list['a','b'],lit['avalue','bvlaue'],string["asc","desc"],string[fiede,field])
      * @param clz   对象类
      * @param pageIndex    当前页
      * @param pageSize        每页数目
      * @param fieldColumns       类的属性数组
      * @param searchValues       类的属性数组对应的值数组
      * @param sortSchemas         每个排序的健数组对应的升降序规则：即ASC,DESC 数组
      * @param sortKeys           排序的健数组
      * @return
      */
    public List<T> getPaginationObjectsWithSimilarCondition(Class clz, final int pageIndex, final int pageSize, List fieldColumns, List searchValues, String[] sortSchemas, String[] sortKeys) {
        Criteria criteria = getSession().createCriteria(clz);
        if (fieldColumns != null && fieldColumns.size() != 0) {
            for (int k = 0; k < fieldColumns.size(); k++) {
                if (searchValues.get(k).getClass().getName().equals("java.lang.String"))
                    criteria.add(Restrictions.like((String) fieldColumns.get(k), ((String) searchValues.get(k)).trim(), MatchMode.ANYWHERE));
                else if (searchValues.get(k).getClass().getName().equals("[Ljava.lang.String;"))
                    criteria.add(Restrictions.in((String) fieldColumns.get(k), (String[]) searchValues.get(k)));
                else if (searchValues.get(k).getClass().getName().equals("[Ljava.lang.Long;"))
                    criteria.add(Restrictions.in((String) fieldColumns.get(k), (Long[]) searchValues.get(k)));
                else
                    criteria.add(Restrictions.eq((String) fieldColumns.get(k), searchValues.get(k)));
            }
        }
        if (sortSchemas != null) {
            for (int k = 0; k < sortSchemas.length; k++) {
                if (sortSchemas[k].equalsIgnoreCase("ASC")) {
                    if (sortKeys[k].indexOf(".") != -1) {
                        String aliasKey = sortKeys[k].substring(0, sortKeys[k].indexOf("."));
                        criteria.createAlias(aliasKey, aliasKey);
                        criteria.addOrder(Order.asc(sortKeys[k]));
                    } else criteria.addOrder(Order.asc(sortKeys[k]));

                } else {
                    if (sortKeys[k].indexOf(".") != -1) {
                        String aliasKey = sortKeys[k].substring(0, sortKeys[k].indexOf("."));
                        criteria.createAlias(aliasKey, aliasKey);
                        criteria.addOrder(Order.desc(sortKeys[k]));
                    } else criteria.addOrder(Order.desc(sortKeys[k]));
                }
            }
        }
        criteria.setFirstResult((pageIndex - 1) * pageSize);
        criteria.setMaxResults(pageSize);
        return criteria.list();
    }

    public List<T> getPaginationObjectsWithSimilarConditionContainCompare(T clz, final int pageIndex, final int pageSize, List fieldColumns, List searchValues,String[] compareColumns, String[] compareDirections, Object[] compareValues,String[] sortSchemas, String[] sortKeys) {
           Criteria criteria = getSession().createCriteria(clz.getClass());
           if(fieldColumns!=null&&fieldColumns.size()!=0)
           {
               for(int k=0;k<fieldColumns.size();k++)
               {
                   if(searchValues.get(k).getClass().getName().equals("java.lang.String"))
                       criteria.add(Restrictions.like((String)fieldColumns.get(k),((String) searchValues.get(k)).trim(), MatchMode.ANYWHERE));
                   else if (searchValues.get(k).getClass().getName().equals("[Ljava.lang.String;"))
                        criteria.add(Restrictions.in((String)fieldColumns.get(k),(String[])searchValues.get(k)));
                   else if (searchValues.get(k).getClass().getName().equals("[Ljava.lang.Long;"))
                     criteria.add(Restrictions.in((String)fieldColumns.get(k),(Long[])searchValues.get(k)));
                   else
                       criteria.add(Restrictions.eq((String)fieldColumns.get(k), searchValues.get(k)));
               }
           }

               if(compareDirections!=null)
               {
                   for(int k=0;k<compareDirections.length;k++)
                  {
                   if(compareDirections[k]!=null){
                       if(compareDirections[k].trim().equalsIgnoreCase("ge")){
                            criteria.add(Restrictions.ge(compareColumns[k], compareValues[k]));
                       }else if (compareDirections[k].trim().equalsIgnoreCase("le")){
                            criteria.add(Restrictions.le(compareColumns[k], compareValues[k]));
                        }else if(compareDirections[k].trim().equalsIgnoreCase("gt"))
                       {
                            criteria.add(Restrictions.gt(compareColumns[k], compareValues[k]));
                       }
                       else if (compareDirections[k].trim().equalsIgnoreCase("lt")){
                            criteria.add(Restrictions.lt(compareColumns[k], compareValues[k]));
                       }else  if(compareDirections[k].trim().equalsIgnoreCase("eq"))
                           criteria.add(Restrictions.eq(compareColumns[k], compareValues[k]));
                       else if (compareDirections[k].trim().equalsIgnoreCase("between"))  //here we can use string token
                           criteria.add(Restrictions.le(compareColumns[k], compareValues[k]));

                       else  if(compareDirections[k].trim().equalsIgnoreCase("like"))
                           criteria.add(Restrictions.like(compareColumns[k], (String)compareValues[k], MatchMode.ANYWHERE));
                   }
                  }
               }

           if(sortSchemas!=null)
           {
               for(int k=0;k<sortSchemas.length;k++)
               {
                   if(sortSchemas[k].equalsIgnoreCase("ASC"))
                   {
                        if(sortKeys[k].indexOf(".")!=-1)
                        {
                            String aliasKey = sortKeys[k].substring(0,sortKeys[k].indexOf("."));
                            criteria.createAlias(aliasKey,aliasKey);
                            criteria.addOrder(Order.asc(sortKeys[k]));
                        }
                        else criteria.addOrder(Order.asc(sortKeys[k]));
                   }
                  else
                   {
                      if(sortKeys[k].indexOf(".")!=-1)
                        {
                            String aliasKey = sortKeys[k].substring(0,sortKeys[k].indexOf("."));
                            criteria.createAlias(aliasKey,aliasKey);
                            criteria.addOrder(Order.desc(sortKeys[k]));
                        }
                        else criteria.addOrder(Order.desc(sortKeys[k]));
                   }
               }
           }
           criteria.setFirstResult((pageIndex-1)*pageSize);
           criteria.setMaxResults(pageSize);
           return criteria.list();
       }


    public Page page(Criteria criteria, int pageNo, int pageSize) {

        int count = countBeans(criteria);
        criteria.setFirstResult((pageNo - 1) * pageSize);
        criteria.setMaxResults(pageSize);

        Page<T> ret = new Page<T>(pageSize, pageNo);
        ret.setTotalCount(count);
        ret.setResult(criteria.list());

        return ret;
    }

    public Page page(Criteria criteria, Page page) {
        return page(criteria, page.getPageNo(), page.getPageSize());
    }

    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            delete(id);
        }
    }

    public void deleteAll(Class clazz, Long[] ids) {
        for (Long id : ids) {
            getSession().delete(getSession().get(clazz, id));
        }
    }
}
